﻿using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;

namespace XNAProjectLibrary
{
    public class GameStateManager : GameComponent, IGameStateManager
    {
        private Stack<GameState> states = new Stack<GameState>();                       //gamestates stack so we can pop and push

        public event EventHandler OnStateChange;                                        //event to notify changed states
                                                                                        //gamestates will sign up for this
        private int initialDrawOrder = 1000;                                            //initial draworder set to 1000 so we can manipulate later
        private int drawOrder;                                                          //for DrawableGameComponent

        public GameStateManager(Game game)
            : base(game)
        {
            game.Services.AddService(typeof(IGameStateManager), this);                  //adds itself to Services to become "GLOBAL"
            drawOrder = initialDrawOrder;                                               //sets draworder to the initial draworder
        }

        public void PopState()
        {
            RemoveState();                                                              //removes top state
            drawOrder -= 100;                                                           //decrease draworder
                         
            if (OnStateChange != null)
                OnStateChange(this, null);                                              //dispatch changestate event to every state
        }                                                                               //states handle or discard it so only the target uses it

        private void RemoveState()
        {
            GameState oldState = (GameState)states.Peek();                              //gets top gamestate

            OnStateChange -= oldState.StateChanged;                                     //unregisters gamestates' event from gamemanager OnStateChanged eventhandler

            Game.Components.Remove(oldState.Value);                                     //removes gamestate from gamecomponents -> doesn't update doesn't draw

            states.Pop();                                                               //takes the gamestate off the stack
        }

        public void PushState(GameState newState)
        {
            drawOrder += 100;                                                           //increase draworder
            newState.DrawOrder = drawOrder;                                             //set new states draworder

            AddState(newState);                                                         //add the new state
 
            if (OnStateChange != null)
                OnStateChange(this, null);                                              //dispatch event
        }
        private void AddState(GameState state)
        {
            states.Push(state);                                                         //push on stack

            Game.Components.Add(state);                                                 //add to the gamecomponents collection

            OnStateChange += state.StateChanged;                                        //register the states event for onstatechange
        }

        public void ChangeState(GameState newState)                                     //resets the stack and adds one state
        {
            while (states.Count > 0)                                                    //pop all states
                RemoveState();

            newState.DrawOrder = drawOrder = initialDrawOrder;                          //reset drawing order
            AddState(newState);                                                         //add new state

            if (OnStateChange != null)
                OnStateChange(this, null);                                              //dispatch event
        }

        public bool ContainsState(GameState state)                                      //check if the state is in the stack
        {
            return (states.Contains(state));
        }


        public GameState State
        {
            get { return (states.Peek()); }                                             //return top state
        }
    }
}
